import React from 'react';
import {
  Avatar, Button, Col, Drawer, Input,
  InputNumber, message, Modal, Popover, Row,
  Switch, Tooltip, Upload,
} from 'antd';
import { Form, Icon } from '@ant-design/compatible';
import { connect } from 'dva';
import { IconButton, PageHeaderLayout, StandardTable, SearchForm, PageCard } from '../../components';
import tools from '../../utils';
import { pageSize, modalWidth, apiUrl, uploadImageSizeUpper } from '../../../config';
import Editor from 'react-umeditor';
import htmlFormat from '../../utils/htmlFormat';
import Authorized from '../../utils/Authorized';

const reqApi = 'content';
const formItemLayout = {
  labelCol: { md: 3 },
  wrapperCol: { md: 21 },
};
const formItemLayout2 = {
  labelCol: { md: 6, xs: 7 },
  wrapperCol: { md: 18, xs: 17 },
};
const formItemLayout4 = {
  labelCol: { md: 10, xs: 7 },
  wrapperCol: { md: 14, xs: 17 },
};
const editorIcons = [
  "bold italic underline strikethrough | forecolor backcolor |",
  "fontsize fontfamily | justifyleft justifycenter justifyright |",
  "spechars inserttable touppercase | indent outdent |",
  "insertorderedlist insertunorderedlist | superscript subscript |",
  "fullscreen | tolowercase",
];
const smallImageLimitSize = 400; // 缩略图限定尺寸(宽和高都不能超过这个值)
const imageLimitSize = 1440; // 源图限定尺寸(宽和高都不能超过这个值)

const editorLoadingImage = require("react-umeditor/dist/images/loading.gif");

class page extends React.Component {
  state = {
    loading: false,
    visible: false,
    dialogLoading: false,
    dialogTitle: "",
    dialogAction: "",
    selectedRows: [],
    searchs: [],
    pagination: {
      current: 1,
      pageSize,
      onShowSizeChange: (_, size) => {
        const { pagination } = this.state;
        pagination.pageSize = size;
      },
    },
    editId: "", // 编辑时记下此id, 等到保存时把此id带过去
    uploading: false, // 是否正在上传封面图片
    uploadingBodyImage: false, // 是否正在上传正文图片
    editorText: "", // 富文本编辑的文字内容
  };

  componentDidMount() {
    this.funcGetListData();
  }

  // 获取列表数据
  funcGetListData = () => {
    this.setState({
      loading: true,
      selectedRows: [], // 换页时清除表格行选中状态
    });

    const { state } = this;
    const { searchs, pagination } = state;
    const { current, pageSize } = pagination;
    const { dispatch } = this.props;

    dispatch({
      type: reqApi + '/list',
      payload: {
        currentPage: current,
        pageSize,
        searchs,
      },
    }).then(() => this.setState({ loading: false }));
  };

  // 表格列
  columns = () => {
    const { props } = this;

    return [
      {
        title: "信息ID",
        dataIndex: "id",
        width: 100,
        render: text => <span style={{ color: "darkgray" }}>{text}</span>,
      },
      {
        title: "信息标题",
        dataIndex: "title",
        type: "text",
        render: (text, record) => {
          const src = this.pathWrap(record.markImg);

          return (
            <div>
              {record.markImg ? (
                <Popover
                  content={(
                    <img
                      src={src}
                      style={{ maxWidth: 300 }}
                      alt=''
                    />
                  )}
                  placement="left"
                >
                  <Avatar
                    icon="picture"
                    shape="square"
                    size="small"
                    src={src}
                    style={{ marginRight: 8 }}
                  />
                </Popover>
              ) : null}
              <Authorized authority={() => tools.funcCheckValid(props, 'edit')} noMatch={text}>
                <a
                  title="编辑"
                  onClick={() => {
                    this.funcOpenForm(record);
                    this.setState({ editId: record.id });
                  }}
                >
                  {text}
                </a>
              </Authorized>
            </div>
          );
        },
      },
      {
        title: '显示顺序',
        dataIndex: 'sequ',
        width: 100,
      },
      {
        title: '首页推荐',
        dataIndex: 'recommend',
        width: 100,
        type: (window.isMobile || window.isPad) ? undefined : 'select',
        sub: [['1', '已推荐'], ['0', '未推荐']],
        render: text =>
          text === "1" ? (
            <Icon
              type="check-circle"
              style={{ color: "limegreen", fontSize: 20 }}
            />
          ) : null,
      },
      {
        title: "创建时间",
        dataIndex: "addTime",
        width: 150,
        render: text => <span style={{ color: "darkgray" }}>{text.substr(0, 16)}</span>,
      },
    ];
  };

  // 记录查询表单提交
  funcOnSubmitSearch = (searchs) => {
    const { state } = this;
    state.pagination.current = 1; // 进行查询操作则将页码归一
    this.setState({ searchs }, this.funcGetListData);
  };

  // 内容列表
  contentTable = () => {
    const { state, props } = this;
    const { data, total } = props[reqApi];

    return (
      <div>
        <SearchForm fields={this.columns()} onSubmit={this.funcOnSubmitSearch} />
        <Button.Group>
          <Authorized authority={() => tools.funcCheckValid(props, 'create')}>
            <IconButton
              text='新增信息'
              onClick={() => this.funcOpenForm()}
              style={{ marginBottom: 16 }}
            />
          </Authorized>
          <Authorized authority={() => tools.funcCheckValid(props, 'delete')}>
            <IconButton
              text='删除信息'
              type='danger'
              onClick={this.funcDelete}
              disabled={!state.selectedRows.length}
              style={{ marginBottom: 16 }}
            />
          </Authorized>
        </Button.Group>
        <StandardTable
          addNum={false}
          loading={state.loading}
          columns={this.columns()}
          data={{
            list: data,
            pagination: { ...state.pagination, total },
          }}
          selectedRows={state.selectedRows}
          onSelectRow={(selectedRows) => this.setState({ selectedRows })}
          onChange={(pageParams) => {
            const { pagination } = this.state;
            pagination.current = pageParams.current;
            this.funcGetListData();
          }}
          scrollX={766}
        />
      </div>
    );
  };

  // 弹出表单
  funcOpenForm = (record) => {
    const dialogAction = record ? 'edit' : 'create';

    this.setState({
      visible: true,
      dialogTitle: tools.funcDlgTitle('信息', dialogAction),
      dialogAction,
      uploading: false,
      editorText: '',
    }, () => {
      const { form, dispatch } = this.props;

      form.resetFields();

      if (dialogAction === 'edit') {
        const { title, markImg, sequ, abstract, id } = record;
        const newRecord = {
          title,
          markImg,
          sequ,
          recommend: record.recommend === "1",
          abstract,
        };
        form.setFieldsValue(newRecord);

        // 调用回显接口获取"content"的值
        dispatch({
          type: reqApi + '/echo',
          payload: {
            action: 'edit',
            id,
          },
        }).then(() => {
          const { props } = this;
          this.setState({
            editorText: props[reqApi].echoModel.content,
          }, this.funcReadyEditor);
        });
      } else setTimeout(this.funcReadyEditor, 0);
    });
  };

  // 删除
  funcDelete = () => {
    const { state } = this;
    let names = [], ids = [];
    for (let i = 0; i < state.selectedRows.length; i += 1) {
      const item = state.selectedRows[i];
      const { id, title } = item;
      names.push(title);
      ids.push(id);
    }

    Modal.confirm({
      title: "删除？",
      content: (
        <div>
          <div>你即将删除以下记录：</div>
          <div>{names + ""}</div>
          <div>请确认是否删除？</div>
        </div>
      ),
      okText: "是",
      okType: "danger",
      cancelText: "否",
      onOk: () => {
        this.setState({ loading: true });

        const { dispatch } = this.props;
        dispatch({
          type: reqApi + '/dele',
          payload: { ids: ids + "" },
        }).then(() => {
          const { props } = this;
          const { success } = props[reqApi];
          if (success) this.funcGetListData();
          else this.setState({ loading: false });
        });
      },
    });
  };

  // 保存
  funcSave = () => {
    const { dialogAction, editId, editorText } = this.state;
    const { form, dispatch } = this.props;

    form.validateFields((error, values) => {
      if (error) return error;

      const model = {
        ...values,
        content: editorText,
      };
      if (dialogAction === "edit") model.id = editId;
      if (!values.userId || values.userId === '0')
        model.userId = tools.funcGetUserId();

      this.setState({ dialogLoading: true });

      dispatch({
        type: reqApi + '/' + dialogAction,
        payload: { model },
      }).then(() => {
        this.setState({ dialogLoading: false });

        const { props } = this;
        const { success } = props[reqApi];
        if (success) {
          this.setState({ visible: false });
          this.funcGetListData();
        }
      });
    });
  };

  // 准备编辑器
  funcReadyEditor = () => {
    // 编辑器的高度自适应
    let dom = document.getElementsByClassName("editable-range")[0];
    if (dom) {
      dom.style.overflow = "auto";
      dom.style.height = "calc(100vh - 421px)";
      dom.setAttribute('dataHeight', 'calc(100vh - 421px)');
    }

    // 修复编辑器工具栏高度
    dom = document.getElementsByClassName("editor-toolbar")[0];
    if (dom) {
      dom.style.lineHeight = "normal";
    }

    // 不用编辑器原有的代码切换, 改为自己实现
    dom = document.getElementsByClassName("icon-tolowercase")[0];
    if (dom) {
      dom.title = "源代码";
      dom.className = "editor-icon icon-source";
      dom.onclick = this.funcToggleSource;
    }

    let txt = document.getElementById("txt_source");
    if (!txt) {
      dom = document.getElementsByClassName("editor-contenteditable-div")[0];
      if (dom) {
        txt = document.createElement("textarea");
        txt.id = "txt_source";
        txt.style.width = "100%";
        txt.style.border = "none";
        txt.style.outline = "none";
        txt.style.backgroundColor = '#002766';
        txt.style.color = '#40a9ff';
        txt.style.lineHeight = "normal";
        txt.style.fontSize = "small";
        txt.style.fontFamily = "monospace";
        txt.style.wordWrap = "normal";
        txt.spellcheck = false;
        txt.onchange = (e) => this.funcEditorChange(e.target.value);
        dom.appendChild(txt);
      }
    }
    txt.style.display = "none";
    txt.style.minHeight = "100px";
    txt.style.height = "calc(100vh - 421px)";
    dom = document.getElementsByClassName("editable-range")[0];
    if (dom) dom.style.display = "block";

    // 上传图片
    dom = document.getElementsByClassName("icon-touppercase")[0];
    if (dom) {
      dom.title = "上传图片";
      dom.className = "editor-icon icon-image";

      const file = document.createElement("input");
      file.type = "file";
      file.accept = "image/*";
      file.style.width = "20px"; // 必须要带单位
      file.style.height = "20px";
      file.style.overflow = "hidden";
      file.style.opacity = 0.02;
      file.onchange = (e) => {
        const thisFile = e.target.files[0];
        if (!thisFile) return;

        const dom = document.getElementsByClassName("icon-image")[0];
        if (dom) {
          dom.children[0].style.display = "none";
          dom.style.backgroundRepeat = "no-repeat";
          dom.style.backgroundPosition = "bottom";
          dom.style.backgroundImage = 'url("' + editorLoadingImage + '")';
        }
        this.setState({ uploadingBodyImage: true }, () => this.funcCheckFile(thisFile));
      };
      dom.appendChild(file);
    }

    // 最大化编辑区
    dom = document.getElementsByClassName('icon-fullscreen')[0];
    if (dom) {
      dom.title = '最大化';
      dom.onclick = this.funcToggleMax;
    }
  };

  // 编辑区内容与代码切换
  funcToggleSource = () => {
    const display = {
      block: "none",
      none: "block",
    };

    let dom = document.getElementsByClassName("editable-range")[0];
    if (dom) {
      dom.style.display = dom.style.display || "block";
      dom.style.display = display[dom.style.display];
    }

    dom = document.getElementById("txt_source");
    if (dom) {
      dom.style.display = display[dom.style.display];
      if (dom.style.display === "block") {
        const { state } = this;
        dom.value = htmlFormat(state.editorText);
      }
    }
  };

  // 编辑区最大化与恢复的切换
  funcToggleMax = () => {
    const dom = document.getElementsByClassName("editable-range")[0];
    if (!dom) return;

    const isWindow = dom.style.height === dom.getAttribute('dataHeight');
    const height = isWindow ? 'calc(100vh - 190px)' : dom.getAttribute('dataHeight');

    dom.style.height = height;

    const txt = document.getElementById("txt_source");
    if (txt) txt.style.height = height;

    const drawerContent = document.getElementById('drawerContent');
    if (drawerContent) {
      drawerContent.style.overflow = isWindow ? 'auto' : 'unset';
      if (isWindow) drawerContent.scrollTop = 231;
    }
  };

  // 编辑器正文更新
  funcEditorChange = (editorText) => {
    const dom = document.getElementById("txt_source");
    if (dom) dom.value = editorText;
    this.setState({ editorText });
  };

  // 检查图片是否有效
  funcCheckFile = (file) => {
    const size = 1024 * 1024 * uploadImageSizeUpper;

    let isOk = true;
    if (file.size > size) {
      message.error(file.name + " 不能超过 " + uploadImageSizeUpper + "MB");
      isOk = false;
    }

    if (isOk) {
      const reader = new FileReader();
      reader.onload = (e) => this.funcDisposeFile(e, file, this.funcUploadFile);
      reader.readAsDataURL(file);
    } else {
      const { state } = this;
      if (state.uploading) this.setState({ uploading: false });
      else if (state.uploadingBodyImage) {
        this.setState({ uploadingBodyImage: false });

        const dom = document.getElementsByClassName("icon-image")[0];
        if (dom) {
          dom.children[0].style.display = "block";
          dom.removeAttribute("style");
        }
      }
    }
    return false;
  };

  // 在源图基础上生成缩略图
  funcDisposeFile = (e, file, callback) => {
    const fileExt = file.name.substr(file.name.lastIndexOf(".") + 1);
    let b64 = e.target.result;
    const img = new Image();
    img.onload = () => {
      // 例外处理, 低分辨率的源图则没必要生成缩略图了
      if (img.width <= smallImageLimitSize && img.height <= smallImageLimitSize) {
        callback(b64.split(",")[1], fileExt);
        return;
      }

      const canvas = document.createElement("canvas");
      const ct = canvas.getContext("2d");

      // 首当其冲，二话不说先对源图进行一次洗礼(压缩)
      canvas.width = img.width;
      canvas.height = img.height;
      ct.drawImage(img, 0, 0, img.width, img.height);
      b64 = canvas.toDataURL(file.type, 0.9);

      // 限制源图尺寸(节省流量并可有效缩短图片加载时间，而且也减少了服务器空间占用)
      // 源图宽度固定是"imageLimitSize"的值
      if (img.width > imageLimitSize) {
        const ratio = img.width / img.height;
        img.width = imageLimitSize;
        img.height = Math.round(imageLimitSize / ratio);

        canvas.width = img.width;
        canvas.height = img.height;
        ct.drawImage(img, 0, 0, img.width, img.height);
        b64 = canvas.toDataURL(file.type, 0.9);
      }

      const { state } = this;
      if (state.uploadingBodyImage) {
        // 上传正文图片不需要生成缩略图
        callback(b64.split(",")[1], fileExt);
        return;
      }

      // 生成缩略图(供列表页面使用，节省流量)
      if (img.width > img.height) {
        const ratio = img.width / img.height;
        if (img.width > smallImageLimitSize) {
          img.width = smallImageLimitSize;
          img.height = Math.round(smallImageLimitSize / ratio);
        }
      } else {
        const ratio = img.height / img.width;
        if (img.height > smallImageLimitSize) {
          img.height = smallImageLimitSize;
          img.width = Math.round(smallImageLimitSize / ratio);
        }
      }

      canvas.width = img.width;
      canvas.height = img.height;
      ct.drawImage(img, 0, 0, img.width, img.height);
      const b64sm = canvas.toDataURL(file.type);

      callback(b64.split(",")[1], fileExt, b64sm.split(",")[1]);
    };
    img.src = b64;
  };

  // 开始上传图片
  funcUploadFile = (b64, imgType, b64sm) => {
    const { dialogAction, editId, uploading } = this.state;
    const payload = {
      b64,
      b64sm,
      imgType,
    };
    if (dialogAction === "edit" && uploading) {
      // 上传封面图片需要指定'contentId', 后台存储时会自动覆盖掉旧的，能够确保只有一张图片，不浪费服务器存储空间,
      // 而上传正文图片则不需要指定'contentId', 因为正文图片可不只一张.
      payload.contentId = editId;
    }
    const { dispatch } = this.props;
    dispatch({
      type: reqApi + '/upload',
      payload,
    }).then(() => {
      const { state, props } = this;
      const { success, uploadUrl } = props[reqApi];
      if (success) {
        if (state.uploading) {
          // 封面图片
          props.form.setFieldsValue({ markImg: uploadUrl });
        } else if (state.uploadingBodyImage) {
          // 正文图片(插入上传后的图片到编辑器正文当中)
          const html = '<div>' +
            '<img src="' + this.pathWrap(uploadUrl) + '"' +
            ' style="max-width:100%;" class="articleImage" alt="" />' +
            '</div>' +
            '<br>';
          state.editorText += html;
        }
      }

      if (state.uploading) this.setState({ uploading: false });
      else if (state.uploadingBodyImage) {
        this.setState({ uploadingBodyImage: false });

        const dom = document.getElementsByClassName("icon-image")[0];
        if (dom) {
          dom.children[0].style.display = "block";
          dom.removeAttribute("style");
        }
      }
    });
  };

  // 包装路径为可访问的网络地址
  pathWrap = path => apiUrl() + '/upload/' + path + '?r=' + new Date().getTime();

  render() {
    const { state, props } = this;
    const { getFieldDecorator } = props.form;

    return (
      <PageHeaderLayout title={props.route.name}>
        <PageCard children={this.contentTable()} />

        <Drawer
          width={window.isMobile ? window.innerWidth : modalWidth}
          title={state.dialogTitle}
          visible={state.visible}
          onClose={() => this.setState({ visible: false })}
          bodyStyle={{ padding: '24px 0 0 0' }}
          footerStyle={{ textAlign: 'right' }}
          footer={[
            <IconButton
              key='cancel'
              text='取消'
              type='default'
              onClick={() => this.setState({ visible: false })}
            />,
            <IconButton
              key='save'
              text='保存'
              loading={state.dialogLoading}
              style={{ marginLeft: 8 }}
              onClick={this.funcSave}
            />,
          ]}
        >
          <div
            id='drawerContent'
            style={{
              padding: '0 24px',
              height: 'calc(100vh - 132px)',
              overflow: 'hidden',
            }}
          >
            <Form>
              <Row gutter={{ md: 24, sm: 8 }}>
                <Col md={24} sm={24}>
                  <Form.Item label="信息标题" {...formItemLayout}>
                    {getFieldDecorator("title", {
                      rules: [{ required: true, message: "请输入信息标题" }],
                    })(<Input maxLength={255} autoFocus />)}
                  </Form.Item>
                </Col>

                <Col md={12} sm={24}>
                  <Form.Item label="封面图片" {...formItemLayout2}>
                    {getFieldDecorator("markImg")(
                      <Input
                        disabled={state.uploading}
                        suffix={
                          state.uploading ? (
                            <Icon type="loading" />
                          ) : (
                            <Upload
                              accept="image/*"
                              showUploadList={false}
                              beforeUpload={(file) => {
                                if (state.uploading) return false;
                                this.setState({ uploading: true }, () => this.funcCheckFile(file));
                              }}
                            >
                              <Tooltip title="选择图片">
                                <Icon type="upload" />
                              </Tooltip>
                            </Upload>
                          )
                        }
                      />
                    )}
                  </Form.Item>
                </Col>

                <Col md={6} sm={24}>
                  <Form.Item label="显示顺序" {...formItemLayout4}>
                    {getFieldDecorator("sequ", {
                      initialValue: 0,
                    })(<InputNumber min={0} max={1000} style={{ width: '100%' }} />)}
                  </Form.Item>
                </Col>

                <Col md={6} sm={24}>
                  <Form.Item label='首页推荐' {...formItemLayout4}>
                    {getFieldDecorator('recommend', {
                      initialValue: true,
                      valuePropName: 'checked',
                    })(<Switch checkedChildren='是' unCheckedChildren='否' />)}
                  </Form.Item>
                </Col>

                <Col span={24}>
                  <Form.Item label="摘要" {...formItemLayout}>
                    {getFieldDecorator("abstract")(
                      <Input.TextArea
                        maxLength={255}
                        rows={3}
                        onFocus={(e) => {
                          const { editorText } = this.state;
                          const dom = document.getElementsByClassName("editable-range")[0];
                          if (!e.target.value && editorText && dom) {
                            // 把下面的富文本编辑器里面的内容的前255个字符作为摘要字段的值
                            props.form.setFieldsValue({ abstract: dom.textContent.substr(0, 255) });
                          }
                        }}
                      />
                    )}
                  </Form.Item>
                </Col>

                <Col span={24}>
                  <Form.Item>
                    <Editor
                      icons={editorIcons}
                      value={state.editorText}
                      onChange={this.funcEditorChange}
                    />
                  </Form.Item>
                </Col>
              </Row>
            </Form>
          </div>
        </Drawer>
      </PageHeaderLayout>
    );
  }
}

const page2 = Form.create()(page);
export default connect(({ content, menu }) => ({ content, menu }))(page2);
